/*
 * Copyright 2013 JROSE
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jrose.webapp.listener;

import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jrose.api.config.ConfigManager;
import org.jrose.core.config.FileSystemAutoScanConfigManagerImpl;
import org.jrose.webapp.remoting.ExposedServiceConfig;
import org.jrose.webapp.remoting.ExposedServiceConfigParser;
import org.jrose.webapp.remoting.ExtendedHttpInvokerProxyFactoryBean;
import org.jrose.webapp.remoting.ExtendedRemoteInvocationFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.remoting.support.RemoteInvocationFactory;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.GenericWebApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import java.util.List;

@NoArgsConstructor
public class ExtendedContextLoaderListener extends ContextLoaderListener {
    private GenericWebApplicationContext applicationContext;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        ServletContext servletContext = event.getServletContext();

        ConfigManager configManager = new FileSystemAutoScanConfigManagerImpl();
        configManager.getCommonConfig();    // trigger configManager initializing

        StaticListableBeanFactory root = new StaticListableBeanFactory();
        root.addBean("configManager", configManager);

        autoImport(root, configManager, servletContext);

        GenericWebApplicationContext gwac = new GenericWebApplicationContext(new DefaultListableBeanFactory(root), servletContext);
        gwac.refresh();
        applicationContext = gwac;

        super.contextInitialized(event);
    }

    @Override
    protected ApplicationContext loadParentContext(ServletContext servletContext) {
        return applicationContext;
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        if (applicationContext != null) {
            applicationContext.close();
        }
        super.contextDestroyed(event);
    }

    private void autoImport(StaticListableBeanFactory root, ConfigManager configManager, ServletContext servletContext) {
        String resourcePath = servletContext.getInitParameter("exposedServices");
        if (StringUtils.isBlank(resourcePath)) {
            return;
        }

        Resource resource = new ClassPathResource(resourcePath, getClass().getClassLoader());
        if (!resource.exists()) {
            return;
        }

        List<ExposedServiceConfig> configs = new ExposedServiceConfigParser(resource, getClass().getClassLoader()).parse();
        if (configs.isEmpty()) {
            return;
        }

        Logger logger = LoggerFactory.getLogger("import.service");
        logger.info("Imported services:");
        String baseUrl = "jrose_service_base_url";
        RemoteInvocationFactory remoteInvocationFactory = new ExtendedRemoteInvocationFactory();
        for (ExposedServiceConfig config : configs) {
            ExtendedHttpInvokerProxyFactoryBean factory = new ExtendedHttpInvokerProxyFactoryBean();
            factory.setBeanClassLoader(getClass().getClassLoader());
            factory.setConfigManager(configManager);
            factory.setServiceUrl(baseUrl + config.getRemoteUrl());
            factory.setServiceInterface(config.getServiceInterface());
            factory.setRemoteInvocationFactory(remoteInvocationFactory);
            factory.afterPropertiesSet();

            Object bean = factory.getObject();
            root.addBean(config.getBeanName(), bean);

            logger.info("[v] {}", config.getServiceInterface().getName());
        }
    }
}
